//-------------------------------------------------------------
// \project PluginExample1
// \file ModuleConditionBranch.java
// \brief 同类型中间结果分支处理
// \author 梁洪国
// \date 2017-12-07
// \attention
// Copyright(c) 超图软件股份有限公司 气象事业部
// All Rights Reserved
// \version 1.0
//-------------------------------------------------------------

package com.mg.pluginexample1;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

import com.mg.model.Model;
import com.mg.model.Module;
import com.mg.model.Param;
import com.mg.model.Port;
import com.mg.model.Model.LogLevel;
import com.mg.model.Port.Type;

public class ModuleConditionBranch extends Module{

	class MyPort extends Port
	{
		public MyPort(Module module) {
			super(module);
			m_strObject ="";
			m_strDataSource = "";
			m_strDataSet ="";
			m_strCon ="";
		}
		
		public Port Clone()
		{
			MyPort mp = new MyPort(null);
			mp.m_strDataSet = m_strDataSet;
			mp.m_strObject = m_strObject;
			mp.m_strDataSet = m_strDataSet;
			mp.m_strCon = m_strCon;
			mp.m_list.addAll(m_list);
			return mp;
		}
		public String m_strObject;
		public String m_strDataSource;
		public String m_strDataSet;
		public List<String> m_list;
		public String m_strCon;
	}
	
	public ModuleConditionBranch(int nID) {
		super(nID);
		m_nId = nID;
		m_alInputPort.add(new MyPort(this));
		m_alInputPort.get(0).SetName("条件");
		m_alOutputPort.add(new Port(this,Port.Type.Unknown));
	}

	public String GetGroupName() {
		return "基本模块";
	}

	public String GetName() {
		return "条件分支";
	}

	public String GetDescription() {
		return "第一个端口指定输入条件，输入多个同类型的中间结果,输出其中一个满足条件的结果";
	}
	
	public boolean  OnAttach(Port fromPort,Port toPort)
	{
		int i = FindPort(fromPort,false);
		if(i != -1)
			return true;
		i = FindPort(toPort,true);
		if (i == -1)
			return false;
		ArrayList<Param> alParam = new ArrayList<Param>();
		fromPort.GetModule().GetOutputParam(fromPort, alParam);

		MyPort mp = (MyPort)toPort;
		if(i==0 && !(alParam.get(0).m_objValue instanceof String))
		{
			m_model.OutputLog(LogLevel.Error,"第一个条件端口只能输入字符类型");
			return false;
		}
		
		if (alParam.size() == 2)// 数据集和数据源
		{
			mp.m_strDataSource = (String) alParam.get(0).m_objValue;
			mp.m_strDataSet = (String) alParam.get(1).m_objValue;
		} 
		else if (alParam.get(0).m_objValue instanceof List<?>) {
			mp.m_list = (List<String>) alParam.get(0).m_objValue;
		} 
		else if (alParam.get(0).m_objValue instanceof String) {
			mp.m_strObject = (String) alParam.get(0).m_objValue;
		}
		else
		{
			m_model.OutputLog(LogLevel.Error,"输入了不支持的类型");
			return false;
		}
		if (i > 1 && fromPort.GetType() != m_alInputPort.get(i - 1).GetType())
		{
			m_model.OutputLog(LogLevel.Error,"这次输入了不同类型");
			return false;
		}
		toPort.SetType(fromPort.GetType());
		if ( i > 0 )
			m_alOutputPort.get(0).SetType(fromPort.GetType());
		
		while (i >= m_alInputPort.size() - 1)
			InsertPort(-1, new MyPort(this), true);
		return true;
	}
	public boolean OnDetach(Port portFrom, Port portTo)
	{
		if (!super.OnDetach(portFrom, portTo))
			return false;
		try
		{
			int i = FindPort(portTo, true);
			if (i == -1)
				return true;
			if (i >= 0 && i < m_alInputPort.size() - 1)
			{
				RemovePort(i, true);
			}
			return true;
		}
		catch (Exception ex)
		{
			ex.printStackTrace();
			return false;
		}
	}
	//界面到xml
	public int GetParam(ArrayList<Param> alParam)
	{
		try{
//			int nOffset = super.GetParam(alParam);
			//-------------------------------------------------------------------------------------------------------------------
			for (int i = 0; i < m_alInputPort.size() - 1; i++)
			{
				MyPort mp = (MyPort)m_alInputPort.get(i);
				if (i ==0)
					alParam.add(new Param("Name", mp.m_strCon, "条件", "如果此处填写了值，则以填写值为准(例：时间请给$DataStartTime)；否则以端口输入值为准", String.format("输入端%d",i)));
				else
				{
					alParam.add(new Param("Name", mp.GetName(), "分支", "", String.format("输入端%d",i)));
					alParam.add(new Param("Name", mp.m_strCon, "输出该分支的条件", "如果是时间条件请输入yyyyMMdd-yyyyMMdd格式,年没有用yyyy替代如：yyyy0831", String.format("输入端%d",i)));
				}
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return alParam.size();
	}
	//xml到参数
	public int SetParam(final ArrayList<Param> alParam)
	{
		int i = super.SetParam(alParam);
		try
		{
			int j = 0;
			while (i < alParam.size())
			{
				MyPort mp = (MyPort)m_alInputPort.get(j);
				if( i > 0)
					mp.SetName((String)alParam.get(i++).m_objValue);
				mp.m_strCon = (String)alParam.get(i++).m_objValue;
				++j;
				if (j == m_alInputPort.size())
					m_alInputPort.add(new MyPort(this));
			}
		}
		catch(Exception e)
		{
			e.printStackTrace();
		}
		return i;
	}
	public boolean Execute()
	{
		String strCondition = "";
		m_iPort = 0;
		if (m_alInputPort.size() <= 1)
		{
			m_model.OutputLog(Model.LogLevel.Error, String.format("\"%s-%d\"模块没有输入数据。", GetNestedName(), GetID()));
			return false;
		}
		else if (m_alInputPort.size() == 2)
		{
			m_model.OutputLog(Model.LogLevel.Error, String.format("\"%s-%d\"模块单个不需要做分支处理。", GetNestedName(), GetID()));
			return false;
		}
		try{
			//第一个端口固定输入条件
			SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
			String strYear =new SimpleDateFormat("yyyy").format(m_model.m_dateDataStart);
			
			MyPort p = ((MyPort)m_alInputPort.get(0));
			strCondition = p .m_strObject;
			if (!p.m_strCon.isEmpty())
				strCondition = p.m_strCon;
			if (strCondition.equalsIgnoreCase("$DataStartTime"))
			{
				strCondition = sdf.format(m_model.m_dateDataStart);
			}
			else if(strCondition.equalsIgnoreCase("$DataEndTime"))
			{
				strCondition = sdf.format(m_model.m_dateDataEnd);
			}
			
			for (int i = 1; i < m_alInputPort.size() - 1; i++)
			{
				MyPort mp = (MyPort)m_alInputPort.get(i);
				if (mp.m_list == null && mp.m_strDataSet.isEmpty() && mp.m_strDataSource.isEmpty() && mp.m_strObject.isEmpty())
				{
					m_model.OutputLog(Model.LogLevel.Error, String.format("\"%s-%d\"模块\"%s\"没有输入数据。", GetNestedName(), GetID(), mp.GetName()));
					return false;
				}
				
				if (!mp.m_strCon.isEmpty())
				{
					if (mp.m_strCon.equals(strCondition))
					{
						m_iPort = i;
						return true;
					}
					
					else if (mp.m_strCon.indexOf('-') != -1)//输入的是时间条件
					{
						Date dtInput = sdf.parse(strCondition);
						String[] strTimes = mp.m_strCon.split("-");
						if (strCondition.equalsIgnoreCase(strTimes[0]))
						{
							m_iPort = i;
							return true;
						}
						
						else if( strTimes.length > 1)
						{
							if (strTimes[0].contains("yyyy"))//年份没有输入
								strTimes[0] = strTimes[0].replace("yyyy", strYear);
							if (strTimes[1].contains("yyyy"))
								strTimes[1] = strTimes[0].replace("yyyy", strYear);
							Date dtSta = sdf.parse(strTimes[0]);
							Date dtEnd = sdf.parse(strTimes[1]);
							Calendar c = Calendar.getInstance();
							if (dtSta.after(dtEnd))
							{
								c.setTime(dtEnd);
								c.add(Calendar.YEAR, 1);
							}
							if(dtInput.before(sdf.parse(strTimes[0])) && dtInput.after(c.getTime()))
							{
								m_iPort = i;
								return true;
							}
						}
					}
				}
			}
		}
		catch (ParseException e)
		{
			e.printStackTrace();
			return false;
		}
		OnParamChanged();
		return true;
	}
	
	public int GetOutputParam(Port port,ArrayList<Param> alParam)
	{
		int i  = FindPort(port,false);
		if (m_iPort == 0&& m_alInputPort.size() > 1)
			m_iPort++;
		MyPort mp =	(MyPort)m_alInputPort.get(m_iPort);
		if (mp.GetType() == Type.DatasetPoint || mp.GetType() == Type.DatasetLine ||mp.GetType() == Type.DatasetRaster)
		{
			alParam.add(new Param("DataSouce",mp.m_strDataSource));
			alParam.add(new Param("DataSet",mp.m_strDataSet));
		}
		else if (mp.GetType() == Type.CSV)
		{
			alParam.add(new Param("CSV",mp.m_list));
		}
		else if(mp.GetType() == Type.Unknown)
		{
			if (mp.m_strObject.isEmpty())
				alParam.add(new Param("Unknow",mp.m_strObject));
			else if (mp.m_list != null)
				alParam.add(new Param("CSV",mp.m_list));
		}
		m_iPort = 0;
		return i;
}	
	int m_nId;
	int m_iPort;
}
